package com.common.domain;


import com.common.convert.Convert;
import com.common.utils.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 筛选
 *
 * @author baixiaoshen
 */
public class Filter extends HashMap<String, Object> {
    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LoggerFactory.getLogger(Filter.class);

    /**
     * 若需要定制查询返回字段，则使用该参数
     * 示例：Filter.addParam("q_status", Filter.QUERY_PARAM);
     */
    public final static String QUERY_PARAM = "param";

    /**
     * 默认构造函数，初始化查询条件
     */
    public Filter() {

    }

    public static Filter EMPTY = new Filter();

    public Filter(String param, String value) {
        this.put(param, value);
    }

    public Filter(Map<String, Object> params) {
        if (params != null && !params.isEmpty()) {
            this.putAll(params);
        }
    }

    /**
     * 批量添加查询条件
     *
     * @param params 封装查询条件的Map
     * @author baixiaoshen
     */
    public Filter addParams(Map<String, Object> params) {
        this.putAll(params);
        return this;
    }

    /**
     * 获取全部的查询条件
     *
     * @return 全部的查询条件
     * @author baixiaoshen
     */
    public Map<String, Object> getAllParams() {
        return this;
    }

    /**
     * 添加一个查询条件
     *
     * @param paramName  查询条件名, 若条件名带"q_", 我们认为该查询项为查询返回值
     * @param paramValue 查询条件值
     * @author baixiaoshen
     */
    public Filter addParam(String paramName, Object paramValue) {
        if (isNotBlank(paramValue)) {
            this.put(paramName, paramValue);
        }
        return this;
    }

    /**
     * 添加一个查询条件，如果查询条件值为空，则取默认值， 不对默认值进行为空判断
     *
     * @param paramName    查询条件名
     * @param paramValue   查询条件值
     * @param defaultValue 默认查询值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addParam(String paramName, Object paramValue, Object defaultValue) {
        if (isNotBlank(paramValue)) {
            this.put(paramName, paramValue);
        } else {
            this.put(paramName, defaultValue);
        }
        return this;
    }

    /**
     * 添加一个Integer类型的查询条件，封装类型转换工作
     *
     * @param paramName  查询条件名
     * @param paramValue 查询条件值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addIntegerParam(String paramName, Object paramValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, Convert.asInt(paramValue));
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Integer类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Integer类型的查询条件，封装类型转换工作， 如果查询条件值为空，则取默认值， 不对默认值进行为空判断
     *
     * @param paramName    查询条件名
     * @param paramValue   查询条件值
     * @param defaultValue 默认查询值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addIntegerParam(String paramName, Object paramValue, Integer defaultValue) {
        try {
            if (isNotBlank(paramValue)) {
                return this.addParam(paramName, Convert.asInt(paramValue));
            } else {
                this.put(paramName, defaultValue);
                return this;
            }
        } catch (Exception e) {
            LOGGER.error("转换Integer类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Long类型的查询条件，封装类型转换工作
     *
     * @param paramName  查询条件名
     * @param paramValue 查询条件值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addLongParam(String paramName, Object paramValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, Convert.asLong(paramValue));
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Long类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Long类型的查询条件，封装类型转换工作， 如果查询条件值为空，则取默认值， 不对默认值进行为空判断
     *
     * @param paramName    查询条件名
     * @param paramValue   查询条件值
     * @param defaultValue 默认查询值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addLongParam(String paramName, Object paramValue, Long defaultValue) {
        try {
            if (isNotBlank(paramValue)) {
                return this.addParam(paramName, Convert.asLong(paramValue));
            } else {
                this.put(paramName, defaultValue);
                return this;
            }
        } catch (Exception e) {
            LOGGER.error("转换Long类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Double类型的查询条件，封装类型转换工作
     *
     * @param paramName  查询条件名
     * @param paramValue 查询条件值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addDoubleParam(String paramName, Object paramValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, Convert.asDouble(paramValue));
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Double类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Double类型的查询条件，封装类型转换工作， 如果查询条件值为空，则取默认值， 不对默认值进行为空判断
     *
     * @param paramName    查询条件名
     * @param paramValue   查询条件值
     * @param defaultValue 默认查询值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addDoubleParam(String paramName, Object paramValue, Double defaultValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, Convert.asDouble(paramValue));
            } else {
                this.put(paramName, defaultValue);
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Double类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个BigDecimal类型的查询条件，封装类型转换工作
     *
     * @param paramName  查询条件名
     * @param paramValue 查询条件值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addBigDecimalParam(String paramName, Object paramValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, new BigDecimal(paramValue.toString()));
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换BigDecimal类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个BigDecimal类型的查询条件，封装类型转换工作， 如果查询条件值为空，则取默认值， 不对默认值进行为空判断
     *
     * @param paramName    查询条件名
     * @param paramValue   查询条件值
     * @param defaultValue 默认查询值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addBigDecimalParam(String paramName, Object paramValue, BigDecimal defaultValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, new BigDecimal(paramValue.toString()));
            } else {
                this.put(paramName, defaultValue);
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换BigDecimal类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Date类型的查询条件，时间格式是：yyyy-MM:dd，封装类型转换工作
     *
     * @param paramName  查询条件名
     * @param paramValue 查询条件值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addDateParam(String paramName, Object paramValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, DateUtil.getDateFromString(paramValue.toString()));
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Double类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Date类型的查询条件，时间格式是：yyyy-MM:dd， 封装类型转换工作， 如果查询条件值为空，则取默认值， 不对默认值进行为空判断
     *
     * @param paramName    查询条件名
     * @param paramValue   查询条件值
     * @param defaultValue 默认查询值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addDateParam(String paramName, Object paramValue, Date defaultValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, DateUtil.getDateFromString(paramValue.toString()));
            } else {
                this.put(paramName, defaultValue);
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Date类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Timestamp类型的查询条件，时间格式是：yyyy-MM:dd HH:mm:ss，封装类型转换工作
     *
     * @param paramName  查询条件名
     * @param paramValue 查询条件值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addTimestampParam(String paramName, Object paramValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, DateUtil.getDateTimeFromString(paramValue.toString()));
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Date类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 添加一个Timestamp类型的查询条件，时间格式是：yyyy-MM:dd HH:mm:ss， 封装类型转换工作，
     * 如果查询条件值为空，则取默认值， 不对默认值进行为空判断
     *
     * @param paramName    查询条件名
     * @param paramValue   查询条件值
     * @param defaultValue 默认查询值
     * @return 当前对象
     * @author baixiaoshen
     */
    public Filter addTimestampParam(String paramName, Object paramValue, Date defaultValue) {
        try {
            if (isNotBlank(paramValue)) {
                this.addParam(paramName, DateUtil.getDateTimeFromString(paramValue.toString()));
            } else {
                this.put(paramName, defaultValue);
            }
            return this;
        } catch (Exception e) {
            LOGGER.error("转换Date类型参数失败：" + paramValue, e);
//            throw new BusinessException(ResultCode.ERROR_SYSTEM_PARAM_FORMAT, e);
        }
        return null;
    }

    /**
     * 判断参数值是否不为空
     *
     * @param paramValue 参数值
     * @return 如果参数值为空，则返回FALSE，如果是String类型，如果是空字符串，也返回FALSE
     * @author baixiaoshen
     * @date 2014年7月29日
     */
    private boolean isNotBlank(Object paramValue) {
        if (paramValue instanceof String) {
            return null != paramValue && !"".equals(paramValue);
        } else {
            return null != paramValue;
        }
    }

    public Object getParam(String paramName) {
        return get(paramName);
    }

    public String getString(String paramName) {
        return Convert.asString(get(paramName));
    }

    /**
     * 返回一个Integer类型的值
     *
     * @param paramName
     * @return
     */
    public Integer getInt(String paramName) {
        return Convert.asInt(get(paramName), -1);
    }

    /**
     * 返回一个Long类型的值
     *
     * @param paramName
     * @return
     */
    public Long getLong(String paramName) {
        return Convert.asLong(get(paramName), -1L);
    }

    public Double getDouble(String paramName) {
        return Convert.asDouble(get(paramName));
    }

    public BigDecimal getBigDecimal(String paramName) {
        return (BigDecimal) get(paramName);
    }

    public Date getDate(String paramName) {
        return (Date) get(paramName);
    }

    /**
     * 构建对象
     *
     * @param clazz
     * @author baixiaoshen
     */
    public <T> T buildBean(Class<T> clazz) {
        try {
            T bean = (T) clazz.newInstance();
            Field[] fields = clazz.getDeclaredFields();
            if (fields != null) {
                for (int i = 0; i < fields.length; i++) {
                    Field field = fields[i];
                    field.setAccessible(true);
                    Object value = get(field.getName());
                    field.set(bean, value);
                }
            }
            return bean;
        } catch (Exception e) {
            LOGGER.error("利用反射将请求参数封装实体出错！", e);
//            TODO: throw new BusinessException(e);
        }
        return null;
    }
}
